//=========================================================================== // CONWAY'S GAME OF LIFE - HENSEL'S COUNTER // ACCELERATED // #1 - Renderings made to a TBitmap // #2 - Unused empty space ignored // if counter and if iterations > 1000 // A world of 857 by 524 // Initial Conditions Designed by Alan Hensel 1994 // Adapted by Nick Gessler 22 April 2007 // Revised by Nick Gessler 10 September 2012 // Revised by Nick Gessler 23 September 2012 //=========================================================================== #include #pragma hdrstop #include // YOU NEED TO TYPE THESE IN #include "Unit1.h" #include "Unit2.h" #include #include #include using namespace std; //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- #define DEAD 0 #define ALIVE 1 #define UNUSED 2 #define RANDOM 2 #define DOT 0 #define GLIDERNW 1 #define GLIDERNE 2 #define GLIDERSE 3 #define GLIDERSW 4 #define OSCILLATOR 5 //=========================================================================== // VARIABLES //=========================================================================== // Normal GOL Variables int thisWorld[857][524], nextWorld[857][524]; int e, s; int relE, relS; int neighbors; bool stop = false; int iterations = 0; int milliseconds = 0; int critterChoice = DOT; TColor background = TColor(0x1F99D3); // Counter GOL Variables bool counter = false; char charLine[100]; AnsiString ansiDataset; AnsiString ansiLine; AnsiString ansiWord; int endLine; int endDollar, endBang; int posDead, posLive; bool dead; int posCode; int row, column; int mult; int rowMult; int line; // Zoom In Magnifier bool magnify; int xMin, yMin; int xMax, yMax; // for Speed-Up #1 Graphics::TBitmap* worldBMP = new Graphics::TBitmap(); Graphics::TBitmap* blowupBMP = new Graphics::TBitmap(); //=========================================================================== // FUNCTIONS //=========================================================================== //-------------------------------------------------------------------- wrap E int wE (int coor) { return (857 + coor) % 857; } //-------------------------------------------------------------------- wrap S int wS (int coor) { return (524 + coor) % 524; } //------------------------------------------------------------ show thisWorld void showThisWorld (void) { worldBMP->Canvas->Brush->Color = background; worldBMP->Canvas->Rectangle(0, 0, worldBMP->Width, worldBMP->Height); blowupBMP->Canvas->Brush->Color = background; blowupBMP->Canvas->Rectangle(0, 0, blowupBMP->Width, blowupBMP->Height); for (int i = 0; i < 857; i++) { for (int j = 0; j < 524; j++) { if (thisWorld[i][j] != ALIVE) { // if DEAD worldBMP->Canvas->Pixels[i][j] = background; if (magnify && i > xMin && i < xMax && j > yMin && j < yMax) { e = i - 1 - xMin; s = j - 1 - yMin; blowupBMP->Canvas->Brush->Color = background; blowupBMP->Canvas->Pen->Color = background; blowupBMP->Canvas->Rectangle (e * 5, s * 5, e * 5 + 5, s * 5 + 5); } } else { // if ALIVE worldBMP->Canvas->Pixels[i][j] = clBlack; if (magnify && i > xMin && i < xMax && j > yMin && j < yMax) { e = i - 1 - xMin; s = j - 1 - yMin; blowupBMP->Canvas->Brush->Color = clBlack; blowupBMP->Canvas->Pen->Color = clBlack; blowupBMP->Canvas->Rectangle (e * 5, s * 5, e * 5 + 5, s * 5 + 5); } } } } if (counter) { // show RED LINE destructor for (int e = 395; e < 460; e++) { worldBMP->Canvas->Pixels[e][258] = clRed; worldBMP->Canvas->Pixels[e][259] = clRed; } } Form1->PaintBox->Canvas->Draw(0, 0, worldBMP); Form1->PaintBox->Canvas->MoveTo(0, 0); Form1->PaintBox->Canvas->LineTo(856, 0); Form1->PaintBox->Canvas->LineTo(856, 523); Form1->PaintBox->Canvas->LineTo(0, 523); Form1->PaintBox->Canvas->LineTo(0, 0); if (magnify) { Form2->PaintBox1->Canvas->Draw(0, 0, blowupBMP); Form2->PaintBox1->Canvas->MoveTo(0, 0); Form2->PaintBox1->Canvas->LineTo(494, 0); Form2->PaintBox1->Canvas->LineTo(494, 369); Form2->PaintBox1->Canvas->LineTo(0, 369); Form2->PaintBox1->Canvas->LineTo(0, 0); Form2->Canvas->MoveTo(0, 0); Form2->Canvas->LineTo(534, 0); Form2->Canvas->LineTo(534, 405); Form2->Canvas->LineTo(0, 405); Form2->Canvas->LineTo(0, 0); } } //------------------------------------------------------------- renderChanges void renderChanges (void) { for (int i = 0; i < 857; i++) { for (int j = 0; j < 524; j++) { if (thisWorld[i][j] != nextWorld[i][j]) { if (nextWorld[i][j] != ALIVE) { // if DEAD worldBMP->Canvas->Pixels[i][j] = clWhite; if (magnify && i > xMin && i < xMax && j > yMin && j < yMax) { e = i - 1 - xMin; s = j - 1 - yMin; blowupBMP->Canvas->Brush->Color = clWhite; blowupBMP->Canvas->Pen->Color = clWhite; blowupBMP->Canvas->Rectangle (e * 5, s * 5, e * 5 + 5, s * 5 + 5); } } else { // if ALIVE worldBMP->Canvas->Pixels[i][j] = clBlack; if (magnify && i > xMin && i < xMax && j > yMin && j < yMax) { e = i - 1 - xMin; s = j - 1 - yMin; blowupBMP->Canvas->Brush->Color = clBlack; blowupBMP->Canvas->Pen->Color = clBlack; blowupBMP->Canvas->Rectangle (e * 5, s * 5, e * 5 + 5, s * 5 + 5); } } } } } Form1->PaintBox->Canvas->Draw(0, 0, worldBMP); Form1->PaintBox->Canvas->MoveTo(0, 0); Form1->PaintBox->Canvas->LineTo(856, 0); Form1->PaintBox->Canvas->LineTo(856, 523); Form1->PaintBox->Canvas->LineTo(0, 523); Form1->PaintBox->Canvas->LineTo(0, 0); if (magnify) { Form2->PaintBox1->Canvas->Draw(0, 0, blowupBMP); Form2->PaintBox1->Canvas->MoveTo(0, 0); Form2->PaintBox1->Canvas->LineTo(494, 0); Form2->PaintBox1->Canvas->LineTo(494, 369); Form2->PaintBox1->Canvas->LineTo(0, 369); Form2->PaintBox1->Canvas->LineTo(0, 0); Form2->Canvas->MoveTo(0, 0); Form2->Canvas->LineTo(534, 0); Form2->Canvas->LineTo(534, 405); Form2->Canvas->LineTo(0, 405); Form2->Canvas->LineTo(0, 0); } } //----------------------------------------------- copy nextWorld to thisWorld void copyNextWorldToThisWorld (void) { for (int i = 0; i < 857; i++) { for (int j = 0; j < 524; j++) { thisWorld[i][j] = nextWorld[i][j]; } } } //---------------------------------------------------- Count Living Neighbors void countLivingNeighbors(void) { neighbors = 0; for (relE = e - 1; relE <= (e + 1); relE++) { for (relS = (s-1); relS <= (s+1 ); relS++) { if ((relE == e) && (relS == s)) continue; if (thisWorld[wE(relE)][wS(relS)] == ALIVE) neighbors++; } } } //-------------------------------------------------------- Compute Next World void computeNextWorld (void) { for (e = 0; e < 857; e++) { for (s = 0; s < 524; s++) { if (counter && (iterations > 1000) && thisWorld[e][s] == UNUSED) { continue; } countLivingNeighbors(); if (thisWorld[e][s] != ALIVE) { // if DEAD if (neighbors == 3) { nextWorld[e][s] = ALIVE; // be born } else { nextWorld[e][s] = thisWorld[e][s]; // else stay dead } } if (thisWorld[e][s] == ALIVE) { // if ALIVE // die at red line (costs 10%) if ((s == 260) && (e > 395 && e < 460)) { nextWorld[e][s] = DEAD; } else if (neighbors == 2 || neighbors == 3) { // stay alive nextWorld[e][s] = ALIVE; } else { // else die nextWorld[e][s] = DEAD; } } } } } //---------------------------------------------------------------------- step void step (void) { iterations++; computeNextWorld(); renderChanges(); copyNextWorldToThisWorld(); Form1->EditIterations->Text = iterations; Sleep(milliseconds); } //----------------------------------------------------------------------- run void run (void) { while (stop == false) { step(); Application->ProcessMessages(); } } //--------------------------------------------------------------------- reset void reset (int choice) { counter = false; iterations = 0; for (int i = 0; i < 857; i++) { for (int j = 0; j < 524; j++) { if (choice == RANDOM) { if (random(2)) thisWorld[i][j] = UNUSED; else thisWorld[i][j] = ALIVE; } if (choice == DEAD) { thisWorld[i][j] = UNUSED; } } } Form1->EditIterations->Text = iterations; } //---------------------------------- decode a line of data ending in a $ or ! void decodeLine (void) { column = 0; // find the DEAD or ALIVE ending delimiter endLine = ansiLine.Length(); while (ansiLine.Length() > 1) { posDead = ansiLine.Pos("b"); posLive = ansiLine.Pos("o"); // is the coding for dead or alive? if (posDead < posLive && posDead != 0) { dead = true; posCode = posDead; } else { dead = false; posCode = posLive; } if (posCode == 0) { // This is a row multiplier ansiWord = ansiLine.SubString(1, ansiLine.Length() - 1); rowMult = ansiWord.ToInt(); ansiLine = ansiLine.SubString(ansiWord.Length() + 1, 1); row += rowMult - 1; Form1->MemoParser->Lines->Add("ROW multiplier " + IntToStr(mult)); Form1->MemoParser->Lines->Add("ROW is now " + IntToStr(row)); Sleep(milliseconds); } if (posCode == 1) { // There is NO cell multiplier if (dead) thisWorld[column + 3][row] = UNUSED; // array inserter else thisWorld[column + 3][row] = ALIVE; // array inserter column++; // array inserter ansiLine = ansiLine.SubString(posCode + 1, ansiLine.Length()); Form1->MemoParser->Lines->Add("1 no multiplier"); Sleep(milliseconds); } if (posCode > 1) { // There IS a cell multiplier ansiWord = ansiLine.SubString(1, posCode - 1); mult = ansiWord.ToInt(); for (int i = 0; i < mult; i++) { // array inserter if (dead) thisWorld[column + 3][row] = UNUSED; // array inserter else thisWorld[column + 3][row] = ALIVE; // array inserter column++; // array inserter } // array inserter ansiLine = ansiLine.SubString(posCode + 1, ansiLine.Length()); Form1->MemoParser->Lines->Add(ansiWord + " multiplier"); Sleep(milliseconds); } Form1->MemoParser->Lines->Add(ansiLine); Sleep(milliseconds); } row++; } //----------------------------------------------------------------- open file void open (void) { reset(DEAD); counter = true; if (Form1->OpenDialog1->Execute()) { ifstream infile(Form1->OpenDialog1->FileName.c_str()); for (int i = 0; i < 100; i++) { infile >> charLine; ansiDataset += charLine; } infile.close(); } Form1->MemoParser->Text = ansiDataset; row = 2; line = 0; for (line = 0; line < 298; line++) { // extract a row of encoded data ending in a $ endLine = ansiDataset.Pos("$"); ansiLine = ansiDataset.SubString(0, endLine); // decode the data from the row and insert it into the world Form1->MemoParser->Lines->Add(" "); Form1->MemoParser->Lines->Add("CODE LINE: " + IntToStr(line)); Form1->MemoParser->Lines->Add("ROW is " + IntToStr(row)); Form1->MemoParser->Lines->Add(ansiLine); Application->ProcessMessages(); Sleep(milliseconds); decodeLine(); // delete the row of encoded data ansiDataset = ansiDataset.SubString (endLine + 1, ansiDataset.Length()); } // extract the last row of encoded data ending in a ! endLine = ansiDataset.Pos("!"); ansiLine = ansiDataset.SubString(0, endLine); // decode the data from the row and insert it into the world Form1->MemoParser->Lines->Add(" "); Form1->MemoParser->Lines->Add("CODE LINE is " + IntToStr(line)); Form1->MemoParser->Lines->Add("ROW is " + IntToStr(row)); Sleep(milliseconds); decodeLine(); ansiDataset = ansiDataset.SubString(endLine + 1, ansiDataset.Length()); showThisWorld(); } //=========================================================================== // EVENT HANDLERS //=========================================================================== //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { // set the sizes of the Bitmaps to the size of the PaintBox worldBMP->Width = 857; worldBMP->Height = 524; blowupBMP->Width = 500; blowupBMP->Height = 375; } //---------------------------------------------------------------- Form Paint void __fastcall TForm1::FormPaint(TObject *Sender) { showThisWorld(); } //----------------------------------------------------------------- Form Show void __fastcall TForm1::FormShow(TObject *Sender) { randomize(); reset(RANDOM); } //-------------------------------------------------- Memo Parser Double Click void __fastcall TForm1::MemoParserDblClick(TObject *Sender) { Form1->MemoParser->Visible = false; showThisWorld(); } //------------------------------------------------------- PaintBox Mouse Move void __fastcall TForm1::PaintBoxMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { Form1->EditX->Text = X; Form1->EditY->Text = Y; Form1->EditValue->Text = thisWorld[X][Y]; } //------------------------------------------------------- PaintBox Mouse Down void __fastcall TForm1::PaintBoxMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if (Button == 1) { // Right Click for Zoom magnify = true; xMin = X - 50; xMax = xMin + 100; yMin = Y - 37; yMax = yMin + 75; Form2->Visible = true; showThisWorld(); } else { // Left Click int e = X; int s = Y; if (e > 6 && s > 6 && e < 840 && s < 510) { // stay away from edges if (critterChoice == DOT) { thisWorld[e][s] = !thisWorld[e][s]; showThisWorld(); } if (critterChoice == GLIDERNW) { thisWorld[e - 1][s ] = ALIVE; thisWorld[e - 1][s - 1] = ALIVE; thisWorld[e - 1][s + 1] = ALIVE; thisWorld[e ][s - 1] = ALIVE; thisWorld[e + 1][s ] = ALIVE; showThisWorld(); } if (critterChoice == GLIDERNE) { thisWorld[e - 1][s - 1] = ALIVE; thisWorld[e ][s - 1] = ALIVE; thisWorld[e + 1][s - 1] = ALIVE; thisWorld[e + 1][s ] = ALIVE; thisWorld[e ][s + 1] = ALIVE; showThisWorld(); } if (critterChoice == GLIDERSE) { thisWorld[e + 1][s - 1] = ALIVE; thisWorld[e - 1][s ] = ALIVE; thisWorld[e + 1][s ] = ALIVE; thisWorld[e ][s + 1] = ALIVE; thisWorld[e + 1][s + 1] = ALIVE; showThisWorld(); } if (critterChoice == GLIDERSW) { thisWorld[e ][s - 1] = ALIVE; thisWorld[e - 1][s ] = ALIVE; thisWorld[e - 1][s + 1] = ALIVE; thisWorld[e ][s + 1] = ALIVE; thisWorld[e + 1][s + 1] = ALIVE; showThisWorld(); } if (critterChoice == OSCILLATOR) { thisWorld[e - 1][s - 4] = ALIVE; thisWorld[e - 1][s - 3] = ALIVE; thisWorld[e - 1][s - 2] = ALIVE; thisWorld[e - 1][s + 2] = ALIVE; thisWorld[e - 1][s + 3] = ALIVE; thisWorld[e - 1][s + 4] = ALIVE; thisWorld[e ][s - 4] = ALIVE; thisWorld[e ][s - 2] = ALIVE; thisWorld[e ][s + 2] = ALIVE; thisWorld[e ][s + 4] = ALIVE; thisWorld[e + 1][s - 4] = ALIVE; thisWorld[e + 1][s - 3] = ALIVE; thisWorld[e + 1][s - 2] = ALIVE; thisWorld[e + 1][s + 2] = ALIVE; thisWorld[e + 1][s + 3] = ALIVE; thisWorld[e + 1][s + 4] = ALIVE; showThisWorld(); } } } } //---------------------------------------------------------- Track Bar Change void __fastcall TForm1::TrackBar1Change(TObject *Sender) { milliseconds = Form1->TrackBar1->Position; } //---------------------------------------------------------------- Run Button void __fastcall TForm1::ButtonRunClick(TObject *Sender) { stop = false; run(); } //--------------------------------------------------------------- Step Button void __fastcall TForm1::ButtonStepClick(TObject *Sender) { stop = true; step(); } //--------------------------------------------------------------- Stop Button void __fastcall TForm1::ButtonStopClick(TObject *Sender) { stop = true; } //------------------------------------------------------------ Refresh Button void __fastcall TForm1::ButtonRepaintClick(TObject *Sender) { showThisWorld(); } //------------------------------------------------------------- Random Button void __fastcall TForm1::ButtonRandomClick(TObject *Sender) { reset(RANDOM); showThisWorld(); } //--------------------------------------------------------------- Dead Button void __fastcall TForm1::ButtonDeadClick(TObject *Sender) { reset(DEAD); showThisWorld(); } //---------------------------------------------------------- Open File Button void __fastcall TForm1::ButtonOpenClick(TObject *Sender) { open(); } //---------------------------------------------------------------- Dot Button void __fastcall TForm1::ImageDotClick(TObject *Sender) { critterChoice = DOT; } //-----------------------------------------------------------NW Glider Button void __fastcall TForm1::ImageGliderNWClick(TObject *Sender) { critterChoice = GLIDERNW; } //-----------------------------------------------------------NE Glider Button void __fastcall TForm1::ImageGliderNEClick(TObject *Sender) { critterChoice = GLIDERNE; } //-----------------------------------------------------------SE Glider Button void __fastcall TForm1::ImageGliderSEClick(TObject *Sender) { critterChoice = GLIDERSE; } //-----------------------------------------------------------SW Glider Button void __fastcall TForm1::ImageGliderSWClick(TObject *Sender) { critterChoice = GLIDERSW; } //--------------------------------------------------------- Oscillator Button void __fastcall TForm1::ImageOscillatorClick(TObject *Sender) { critterChoice = OSCILLATOR; } //----------------------------------------------------------------------- End void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { delete worldBMP; delete blowupBMP; } //---------------------------------------------------------------------------